/*
HttpSharp: Modular HTTP server C# library targeting .NET/Mono
Copyright 2009 Thesis Kongpakdeepong

This file is part of HttpSharp.

HttpSharp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

HttpSharp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with HttpSharp.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;

namespace HttpSharp
{
  public class Server
  {
    public event ProcessRequestDelegate OnProcessRequest;
    
    private ServerStatus _status;
    public ServerStatus Status
    {
      get { return _status; }
      private set { _status = value; }
    }
    
    private List<int> _ports = new List<int>();
    public IList<int> Ports
    {
      get { return _ports.AsReadOnly(); }
      set
      {
        if(Status != ServerStatus.Stopped)
        {
          throw new InvalidOperationException("Status != ServerStatus.Stopped");
        }
        if(value == null)
        {
          throw new ArgumentNullException("value");
        }
        _ports = new List<int>(value);
      }
    }
    
    private TcpListener[] _listeners;
    
    private void AcceptSocket(IAsyncResult result)
    {
      TcpListener listener = (TcpListener)result.AsyncState;
      using(Socket connection = listener.EndAcceptSocket(result))
      {
        listener.BeginAcceptSocket(AcceptSocket,listener);
        ProcessResults processResult = ProcessResults.None;
        do
        {
          HttpRequest request = new HttpRequest(connection);
          foreach(ProcessRequestDelegate handler in OnProcessRequest.GetInvocationList())
          {
            processResult = handler(request);
            if((processResult | ProcessResults.Handled) == ProcessResults.Handled)
            {
              break;
            }
          }
        }
        while ((processResult | ProcessResults.KeepAlive) == ProcessResults.KeepAlive);
      }
    }
    
    
    public void Start()
    {
      if(Status != ServerStatus.Stopped)
      {
        throw new InvalidOperationException("Status != ServerStatus.Stopped");
      }
      Status = ServerStatus.Starting;
      if(Ports.Count < 1)
      {
        throw new InvalidOperationException("Ports.Count < 1");
      }
      if(OnProcessRequest == null)
      {
        throw new InvalidOperationException("OnProcessRequest == null");
      }
      _listeners = new TcpListener[Ports.Count];
      for(int i = 0; i < Ports.Count; i++)
      {
        _listeners[i] = new TcpListener(IPAddress.Any,Ports[i]);
      }
      foreach(TcpListener listener in _listeners)
      {
        listener.Start();
        listener.BeginAcceptSocket(AcceptSocket,listener);
      }
      Status = ServerStatus.Running;
    }
    
    public void Stop()
    {
      if(Status != ServerStatus.Running)
      {
        throw new InvalidOperationException("Status != ServerStatus.Running");
      }
      Status = ServerStatus.Stopping;
      foreach(TcpListener listener in _listeners)
      {
        listener.Stop();
      }
      Status = ServerStatus.Stopped;
    }
  }
}